//
//  UIView+Constraints.swift
//  BasicTools
//
//  Created by Ting Han on 2022/3/11.
//

import Foundation
import UIKit

struct AnchorExtended<T> {
    let value: T
}

protocol AnchorProtocol {
    associatedtype T
    
    var anchor: AnchorExtended<T> { set get }
    static var anchor: AnchorExtended<T>.Type { set get }
}

extension AnchorProtocol {
    var anchor: AnchorExtended<Self> {
        set {}
        get { AnchorExtended(value: self) }
    }
    static var anchor: AnchorExtended<Self>.Type {
        set {}
        get { AnchorExtended<Self>.self }
    }
}

extension UIView: AnchorProtocol {}

extension AnchorExtended where T: UIView {
    
    @discardableResult
    func fill(_ relativeView: UIView? = nil, edage: UIEdgeInsets = .zero) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: edage.left).isActive = true
        value.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: edage.right).isActive = true
        value.topAnchor.constraint(equalTo: view.topAnchor, constant: edage.top).isActive = true
        value.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: edage.bottom).isActive = true
        return value
    }
    
    @discardableResult
    func leading(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func leading(anchor: NSLayoutXAxisAnchor, offset: CGFloat = 0) -> T {
        value.leadingAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func left(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.leftAnchor.constraint(equalTo: view.leftAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func left(anchor: NSLayoutXAxisAnchor, offset: CGFloat = 0) -> T {
        value.leftAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func trailing(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func trailing(anchor: NSLayoutXAxisAnchor, offset: CGFloat = 0) -> T {
        value.trailingAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func right(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.rightAnchor.constraint(equalTo: view.rightAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func right(anchor: NSLayoutXAxisAnchor, offset: CGFloat = 0) -> T {
        value.rightAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func top(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.topAnchor.constraint(equalTo: view.topAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func top(anchor: NSLayoutYAxisAnchor, offset: CGFloat = 0) -> T {
        value.topAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func bottom(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func bottom(anchor: NSLayoutYAxisAnchor, offset: CGFloat = 0) -> T {
        value.bottomAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func centerX(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func centerX(anchor: NSLayoutXAxisAnchor, offset: CGFloat = 0) -> T {
        value.centerXAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func centerY(_ relativeView: UIView? = nil, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func centerY(anchor: NSLayoutYAxisAnchor, offset: CGFloat = 0) -> T {
        value.centerYAnchor.constraint(equalTo: anchor, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func center(_ relativeView: UIView? = nil, offset: CGPoint = .zero) -> UIView {
        let view: UIView = relativeView ?? value.superview ?? value
        value.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: offset.x).isActive = true
        value.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: offset.y).isActive = true
        return value
    }
    
    @discardableResult
    func width(_ relativeView: UIView? = nil, multiplier: CGFloat = 1, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: multiplier, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func width(anchor: NSLayoutDimension, multiplier: CGFloat = 1, offset: CGFloat = 0) -> T {
        value.widthAnchor.constraint(equalTo: anchor, multiplier: multiplier, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func width(constant width: CGFloat) -> T {
        value.widthAnchor.constraint(equalToConstant: width).isActive = true
        return value
    }
    
    @discardableResult
    func height(_ relativeView: UIView? = nil, multiplier: CGFloat = 1, offset: CGFloat = 0) -> T {
        let view: UIView = relativeView ?? value.superview ?? value
        value.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: multiplier, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func height(anchor: NSLayoutDimension, multiplier: CGFloat = 1, offset: CGFloat = 0) -> T {
        value.heightAnchor.constraint(equalTo: anchor, multiplier: multiplier, constant: offset).isActive = true
        return value
    }
    
    @discardableResult
    func height(constant width: CGFloat) -> T {
        value.heightAnchor.constraint(equalToConstant: width).isActive = true
        return value
    }
    
    @discardableResult
    func size(_ relativeView: UIView? = nil, multiplier: CGFloat = 1, offset: CGPoint = .zero) -> UIView {
        let view: UIView = relativeView ?? value.superview ?? value
        value.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: multiplier, constant: offset.x).isActive = true
        value.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: multiplier, constant: offset.y).isActive = true
        return value
    }
    
    @discardableResult
    func size(constant size: CGSize) -> UIView{
        value.widthAnchor.constraint(equalToConstant: size.width).isActive = true
        value.heightAnchor.constraint(equalToConstant: size.height).isActive = true
        return value
    }
}


/*
example:

 func block<T>(value: T,  closure: (T) -> Void) -> T{
     closure(value)
     return value
 }
 
 let red = block(value: UIView()) {
     $0.backgroundColor = .red
     $0.translatesAutoresizingMaskIntoConstraints = false
 }

 let green: UIView = {
     $0.backgroundColor = .green
     $0.translatesAutoresizingMaskIntoConstraints = false
    return $0
 }(UIView())
 
 view.addSubview(red)
 view.addSubview(green)
 
 ///  usage:
 red.anchor.fill(nil, edage: UIEdgeInsets(top: 200, left: 100, bottom: -200, right: -100))
 green.anchor.leading(nil, offset: 100)
     .anchor.trailing(nil, offset: -100)
     .anchor.height(constant: 200)
     .anchor.top(nil, offset: 300)
 
 */
